package com.zyk.leetcode;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * @author zhangsan
 * @date 2021/4/7 10:27
 */
public class C1114 {

    static class Foo {

        // cas实现
        AtomicBoolean firstJobDone = new AtomicBoolean(false);
        AtomicBoolean secondJobDone = new AtomicBoolean(false);
        public Foo() {
        }
        public void first(Runnable printFirst) throws InterruptedException {

            // printFirst.run() outputs "first". Do not change or remove this line.
            printFirst.run();
            firstJobDone.compareAndExchange(false, true);
        }

        public void second(Runnable printSecond) throws InterruptedException {
            while (! firstJobDone.get()) {
                // first没做完我就自旋
            }
            // printSecond.run() outputs "second". Do not change or remove this line.
            printSecond.run();
            secondJobDone.compareAndExchange(false, true);
        }

        public void third(Runnable printThird) throws InterruptedException {
            while (!secondJobDone.get()) {
                // second没做完我就自选
            }
            // printThird.run() outputs "third". Do not change or remove this line.
            printThird.run();
        }
    }

    static class Foo2 {

        // 锁实现
        boolean firstJobDone = false;
        boolean secondJobDone = false;
        private Object lock = new Object();
        public Foo2() {
        }
        public void first(Runnable printFirst) throws InterruptedException {

            // printFirst.run() outputs "first". Do not change or remove this line.
            synchronized (lock) {
                printFirst.run();
                firstJobDone = true;
                lock.notifyAll();
            }
        }

        public void second(Runnable printSecond) throws InterruptedException {
            synchronized (lock) {
                while (!firstJobDone) {
                    // first没做完我就自旋
                    lock.wait();
                }
                // printSecond.run() outputs "second". Do not change or remove this line.
                printSecond.run();
                secondJobDone = true;
                lock.notifyAll();
            }
        }

        public void third(Runnable printThird) throws InterruptedException {
            synchronized (lock) {
                while (!secondJobDone) {
                    // second没做完我就自选
                    lock.wait();
                }
                // printThird.run() outputs "third". Do not change or remove this line.
                printThird.run();
            }
        }
    }

    static class Foo3 {

        // CountDownLatch 实现
        CountDownLatch secondLatch = new CountDownLatch(1);
        CountDownLatch thirdLatch = new CountDownLatch(1);

        public Foo3() {
        }

        public void first(Runnable printFirst) throws InterruptedException {

            // printFirst.run() outputs "first". Do not change or remove this line.
            // 一号任务 风雨无阻 , 运行完毕帮二号任务解开
            printFirst.run();
            secondLatch.countDown();
        }

        public void second(Runnable printSecond) throws InterruptedException {
            // 二号, 上来现阻塞, 等着一号运行帮他解开
            secondLatch.await();
            printSecond.run();
            thirdLatch.countDown();
        }

        public void third(Runnable printThird) throws InterruptedException {
            // 三号, 上来现阻塞, 等着二号运行帮他解开
            thirdLatch.await();
            printThird.run();
        }
    }

    static class Foo4 {

        // 同步队列SynchronousQueue实现
        // 如果获取不到值, 线程就会在这里阻塞
        BlockingQueue<Integer> secondQueue, thirdQueue;

        public Foo4() {
            secondQueue = new SynchronousQueue<>();
            thirdQueue = new SynchronousQueue<>();
        }

        public void first(Runnable printFirst) throws InterruptedException {

            // printFirst.run() outputs "first". Do not change or remove this line.
            // 一号任务 风雨无阻 , 运行完毕帮二号任务解开
            printFirst.run();
            secondQueue.put(0);
        }

        public void second(Runnable printSecond) throws InterruptedException {
            // 二号, 上来现阻塞, 等着一号运行帮他解开
            secondQueue.take();
            printSecond.run();
            thirdQueue.put(0);
        }

        public void third(Runnable printThird) throws InterruptedException {
            // 三号, 上来现阻塞, 等着二号运行帮他解开
            thirdQueue.take();
            printThird.run();
        }
    }


    // for test
    public static void main(String[] args) throws InterruptedException {
        Foo4 foo = new Foo4();
        Thread thread = new Thread(()-> {
            System.out.println("first");
        }, "1");
        Thread thread2 = new Thread(()-> {
            System.out.println("second");
        }, "2");
        Thread thread3 = new Thread(()-> {
            System.out.println("third");
        }, "3");

        foo.first(thread);
        foo.second(thread2);
        foo.third(thread3);
    }

}
